package com.jfinal.weixin.api;

/**
 * @author LarryKoo(larrykoo@126.com)
 * @date 2015-12-25
 */

import com.alibaba.fastjson.JSON;
import com.jfinal.utils.Exceptions;
import com.jfinal.utils.RetryUtils;
import com.jfinal.utils.http.HttpUtil;
import com.jfinal.weixin.api.model.Follower;
import com.jfinal.weixin.api.model.SnsAccessToken;
import org.apache.commons.lang3.StringUtils;

import java.util.concurrent.Callable;

/**
 * 授权获取用户基本信息接口
 */
public enum UserOauth2Api {
    ice;

    /**
     * 组装授权链接源地址
     *
     * @param appId       公众号的唯一标识
     * @param redirectUrl 授权后重定向的回调链接地址，请使用urlencode对链接进行处理
     * @param scope       应用授权作用域，snsapi_base （不弹出授权页面，直接跳转，只能获取用户openid），
     *                    snsapi_userinfo （弹出授权页面，可通过openid拿到昵称、性别、所在地。
     *                    并且，即使在未关注的情况下，只要用户授权，也能获取其信息）
     * @param state       重定向后会带上state参数，开发者可以填写a-zA-Z0-9的参数值，最多128字节
     * @return
     */
    public String getOauthURL(String appId, String redirectUrl, String scope, String state) {
        String url = APIConfig.WX__USER_OAUTH_URL;
        url = url.replace("APPID", appId)
                .replace("REDIRECT_URI", redirectUrl)
                .replace("SCOPE", scope)
                .replace("STATE", state);

        return url;
    }

    /**
     * 通过code换取网页授权access_token
     *
     * @param appid  公众号的唯一标识
     * @param secret 公众号的appsecret
     * @param code   填写第一步获取的code参数
     * @return
     */
    public SnsAccessToken getSnsAccessToken(String appid, String secret, String code) {
        String url = APIConfig.WX__USER_OAUTH_AUTHORIZE;
        url = url.replace("APPID", appid)
                .replace("SECRET", secret)
                .replace("CODE", code);

        final String finalUrl = url;

        //失败时重试三次
        SnsAccessToken accessToken = RetryUtils.retryOnException(3, new Callable<SnsAccessToken>() {
            @Override
            public SnsAccessToken call() throws Exception {
                ApiResult apiResult = ApiResult.create(HttpUtil.get(finalUrl));
                return JSON.parseObject(apiResult.getJson(), SnsAccessToken.class);
            }
        });

        if (accessToken != null && accessToken.getAccess_token() != null && accessToken.getExpires_in() > 0) {
            return accessToken;
        }
        return null;
    }

    /**
     * 刷新access_token（如果需要）
     *
     * @param appid         公众号的唯一标识
     * @param refresh_token 填写通过access_token获取到的refresh_token参数
     * @return
     */
    public SnsAccessToken refreshSnsAccessToken(String appid, String refresh_token) {
        String url = APIConfig.WX__USER_OAUTH_AUTHORIZE_REFRESH;
        url = url.replace("APPID", appid)
                .replace("REFRESH_TOKEN", refresh_token);

        final String finalUrl = url;

        //失败时重试三次
        SnsAccessToken accessToken = RetryUtils.retryOnException(3, new Callable<SnsAccessToken>() {
            @Override
            public SnsAccessToken call() throws Exception {
                ApiResult apiResult = ApiResult.create(HttpUtil.get(finalUrl));
                return JSON.parseObject(apiResult.getJson(), SnsAccessToken.class);
            }
        });

        if (accessToken != null && accessToken.getAccess_token() != null && accessToken.getExpires_in() > 0) {
            return accessToken;
        }
        return null;
    }

    /**
     * 拉取用户信息(需scope为 snsapi_userinfo)
     *
     * @param access_token 网页授权接口调用凭证,注意：此access_token与基础支持的access_token不同
     * @param openid       用户的唯一标识
     * @return
     */
    public ApiResult getUserInfo(String access_token, String openid) {
        String url = APIConfig.WX__USER_OAUTH_USERINFO;
        url = url.replace("ACCESS_TOKEN", access_token);
        url = url.replace("OPENID", openid);

        return ApiResult.create(HttpUtil.get(url));
    }

    /**
     * 转换json数据为UserInfo对象
     *
     * @param dataJson json数据
     * @return
     */
    public Follower convertFollower(String dataJson) {
        Follower userInfo = null;
        try {
            if (StringUtils.isNotBlank(dataJson)) {
                userInfo = JSON.parseObject(dataJson, Follower.class);
            }
        } catch (Exception e) {
            throw Exceptions.unchecked(e);
        }
        return userInfo;
    }

}
